/* ******************************************** */
/* * Next Generation Creator                  * */
/* * Authors: André Bannwart Perina           * */
/* *          Antonio Canabrava Fraideinberze * */
/* *          Willian Felipe Lopes da Silva   * */
/* ******************************************** */

#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <vector>
#include <climits>
#include <utility>
#include <map>

using namespace std;

/**
 * Program that opens the fitness files, do some sort of filtering based on
 * what we want, then on those that accomplished the goal, we apply a random
 * cross-over with a random sibling and random gene
 */
int main(int argc, char *argv[]) {
    if(argc != 6) {
    	fprintf(stderr, "Usage: ./fit deltaSize numberOfIter percentage crossOver mutation\n");
        fprintf(stderr, "\tPercentage = 0.3: Best 30 percent\n");
        fprintf(stderr, "\tCrossover = 0.7: 70 percent of change of happenning crossover\n");
        fprintf(stderr, "\tMutation = 0.01: 1 percent of change of happenning mutation\n");
    	return EXIT_FAILURE;
    }

    srand(time(NULL));

    FILE * pFile1;
    FILE * pFile2;
    FILE * winners;

    double score;
    double percentage = atof(argv[3]);
    double cross_over = atof(argv[4]);
    double mutation = atof(argv[5]);
    double prob;
    double gene1;
    double geneAux1;
    double geneAux2;

    int fileNum;
    int deltaSize = atoi(argv[1]);
    int numIter = atoi(argv[2]);

    int indiv1;
    int indiv2;
    int coPoint;

    int indivM;
    int mPoint;

    char * fileName1 = (char *) malloc(((numIter / 10) + 20) * sizeof(char));
    char * fileName2 = (char *) malloc(((numIter / 10) + 20) * sizeof(char));

    vector<vector<double> > individuals;

    vector<double> indivVec1;
    vector<double> indivVec2;
    vector<double> indivVecM;

    if((winners = fopen("tournament/data.dat", "r")) == NULL) {
        fprintf(stderr, "Could not open the file tournament/data.dat.\n");
        return EXIT_FAILURE;
    }

    // Opens the winners file to get all the tournament winners
    while(!feof(winners)) {
        fscanf(winners, "%d %lf", &fileNum, &score);
        sprintf(fileName1, "deltaFiles/file_%d", fileNum);

        // Stores all the individuals
        if((pFile1 = fopen(fileName1, "r")) != NULL) {
            fscanf(pFile1, "%d", &gene1);
            for(int i = 0; i < deltaSize; i++) {
                fscanf(pFile1, "%lf", &gene1);
                indivVec1.push_back(gene1);
            }

            individuals.push_back(indivVec1);
            indivVec1.clear();
            fclose(pFile1);
        }
    }

    fclose(winners);

    for(int i = 0; i < individuals.size(); i++) {
        // Cross-over
        prob = (rand() % 10) / 10.0;
        fprintf(stderr, "prob crossover: %lf\n", prob);
        if(prob <= cross_over) {
            // Selects the individuals
            indiv1 = i;
            do {
                indiv2 = rand() % individuals.size();
            } while(indiv1 == indiv2);

            // Selects the cross-over point
            coPoint = rand() % deltaSize;

            fprintf(stderr, "indiv1: %d indiv2: %d coPoint: %d\n", indiv1, indiv2, coPoint);
            for(int i = coPoint; i < deltaSize; i++) {
                geneAux1 = individuals[indiv1][i];
                geneAux2 = individuals[indiv1][i];

                individuals[indiv1][i] = geneAux2;
                individuals[indiv1][i] = geneAux1;
            }
        }

        // Mutation
        prob = (rand() % 100) / 100.0;
        fprintf(stderr, "prob mut: %lf\n", prob);
        if(prob <= mutation) {
            indivM = i;
            mPoint = rand() % deltaSize;

            fprintf(stderr, "indiv1: %d mutation point: %d\n", indiv1, mPoint);
            individuals[indivM][mPoint] = ((rand() % 2) ? 1 : -1) * (rand() % 10) / 10.0;
        }
    }

    // Saves the new individuals to the files
    for(int i = 0; i < individuals.size(); i++) {
        sprintf(fileName1, "deltaFiles/file_%d", i);
        if((pFile1 = fopen(fileName1, "w")) != NULL) {
            fprintf(pFile1, "%d\n", deltaSize);

            for(int j = 0; j < deltaSize; j++) {
                fprintf(pFile1, "%lf ", individuals[i][j]);
            }

            fclose(pFile1);            
        }
    }

    free(fileName1);
    free(fileName2);

    return EXIT_SUCCESS;
}
